package com.gzx.plugin.tjzy.modular.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fhs.trans.service.impl.DictionaryTransService;
import com.gzx.plugin.tjzy.core.entity.CustomVo;
import com.gzx.plugin.tjzy.modular.company.entity.GzxCompany;
import com.gzx.plugin.tjzy.modular.company.mapper.GzxCompanyMapper;
import com.gzx.plugin.tjzy.modular.product.entity.GzxProduct;
import com.gzx.plugin.tjzy.modular.product.mapper.GzxProductMapper;
import com.gzx.plugin.tjzy.modular.project.entity.GzxProject;
import com.gzx.plugin.tjzy.modular.project.entity.bo.GzxProjectBo;
import com.gzx.plugin.tjzy.modular.project.entity.bo.GzxProjectIdBo;
import com.gzx.plugin.tjzy.modular.project.entity.bo.GzxProjectQueryBo;
import com.gzx.plugin.tjzy.modular.project.entity.bo.GzxProjectTileBo;
import com.gzx.plugin.tjzy.modular.project.entity.vo.GzxProjectVo;
import com.gzx.plugin.tjzy.modular.project.mapper.GzxProjectMapper;
import com.gzx.plugin.tjzy.modular.project.service.GzxProjectListService;
import com.gzx.plugin.tjzy.modular.project.service.GzxProjectService;
import com.gzx.plugin.tjzy.modular.project.belong.service.GzxProjectBelongService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import vip.xiaonuo.common.consts.GzxDictConstant;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.tenant.TenantContext;
import vip.xiaonuo.common.util.MapstructUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 委托公司产品项目Service业务层处理
 *
 * @author LionLi
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class GzxProjectServiceImpl implements GzxProjectService, InitializingBean {

    private final GzxProjectMapper baseMapper;

    private final GzxProductMapper productMapper;

    private final GzxCompanyMapper companyMapper;

    private final DictionaryTransService dictionaryTransService;

    private final GzxProjectListService projectListService;

    private final GzxProjectBelongService projectBelongService;

    /**
     * 根据项目编码获取产品编码
     */
    @DS("tjzy")
    public String getProductCodeByProjectCode(String projectCode) {
        GzxProject gzxProject = baseMapper.selectOne(new LambdaQueryWrapper<GzxProject>().eq(GzxProject::getProjectCode, projectCode));
        return (!ObjectUtils.isEmpty(gzxProject) ? gzxProject.getProductCode() : "");
    }

    /**
     * 分页查询委托公司产品项目列表
     *
     * @param projectQueryBo 查询条件
     * @return 委托公司产品项目分页列表
     */
    @Override
    @DS("tjzy")
    public Page<GzxProjectVo> pageList(GzxProjectQueryBo projectQueryBo) {
        LambdaQueryWrapper<GzxProject> lqw = buildQueryWrapper(projectQueryBo);
        lqw.select(GzxProject::getId,
                GzxProject::getProductCode,
                GzxProject::getProjectCode,
                GzxProject::getBelongDirector,
                GzxProject::getBelongTeam,
                GzxProject::getProjectName,
                GzxProject::getProjectDescription,
                GzxProject::getCaseLoad,
                GzxProject::getDebtUser,
                GzxProject::getPhoneAmount,
                GzxProject::getPhoneFreezeAmount,
                GzxProject::getSmsAmount,
                GzxProject::getSmsFreezeAmount
        );
        Page<GzxProjectVo> result = baseMapper.selectVoPage(new Page<>(projectQueryBo.getCurrent(), projectQueryBo.getSize()), lqw);
        // 计算amount字段：余额 - 冻结金额
        result.getRecords().forEach(project -> {
            BigDecimal amount = project.getSmsAmount().subtract(project.getSmsFreezeAmount());
            project.setSmsAmount(amount);
        });
        setProductName(result.getRecords());
        return result;
    }

    /**
     * 查询委托公司产品项目
     *
     * @param id 主键
     * @return 委托公司产品项目
     */
    @Override
    @DS("tjzy")
    public GzxProjectVo queryById(Long id) {
        GzxProjectVo gzxProjectVo = baseMapper.selectVoById(id);
        setProductName(gzxProjectVo);
        return BeanUtil.toBean(gzxProjectVo, GzxProjectVo.class);
    }

    @Override
    @DS("tjzy")
    public List<CustomVo> listAll(boolean flag, String val) {
        LambdaQueryWrapper<GzxProject> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(val)) {
            if (flag) {
                lqw.like(GzxProject::getProjectName, val).or().like(GzxProject::getProjectCode, val);
            } else {
                lqw.like(GzxProject::getProductCode, val);
            }
        }
        return convertList(baseMapper.selectVoList(lqw));
    }

    private LambdaQueryWrapper<GzxProject> buildQueryWrapper(GzxProjectQueryBo bo) {
        LambdaQueryWrapper<GzxProject> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getProductCode() != null, GzxProject::getProductCode, bo.getProductCode());
        lqw.eq(StringUtils.isNotBlank(bo.getProjectCode()), GzxProject::getProjectCode, bo.getProjectCode());
        lqw.like(StringUtils.isNotBlank(bo.getProjectName()), GzxProject::getProjectName, bo.getProjectName());
        lqw.eq(StringUtils.isNotBlank(bo.getProjectDescription()), GzxProject::getProjectDescription, bo.getProjectDescription());
        lqw.orderByDesc(GzxProject::getId);
        return lqw;
    }

    /**
     * 新增委托公司产品项目
     *
     * @param bo 委托公司产品项目
     */
    @Override
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    public void insertByBo(GzxProjectBo bo) {
        //校验唯一项目编码是否存在
        verifyProjectCode(bo.getProjectCode(), null);
        GzxProject target = MapstructUtils.convert(bo, GzxProject.class);
        target.setBelongDirector(bo.getBelongDirector());
        target.setBelongTeam(bo.getBelongTeam());
        baseMapper.insert(target);
        //保存关联表数据
        projectBelongService.insertBelong(bo);
        refreshTransCache();
    }

    /**
     * 修改委托公司产品项目
     *
     * @param bo 委托公司产品项目
     */
    @Override
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    public void updateByBo(GzxProjectBo bo) {
        verifyProjectCode(bo.getProjectCode(), bo.getId());
        GzxProject target = MapstructUtils.convert(bo, GzxProject.class);
        target.setBelongDirector(bo.getBelongDirector());
        target.setBelongTeam(bo.getBelongTeam());
        baseMapper.updateById(target);
        //保存关联表数据
        projectBelongService.updateBelong(bo);
        refreshTransCache();
    }

    /**
     * 校验并批量删除委托公司产品项目信息
     *
     * @param projectIdBo 删除ID列表业务对象
     */
    @Override
    @DS("tjzy")
    public void deleteWithValidByIds(GzxProjectIdBo projectIdBo) {
        baseMapper.deleteBatchIds(projectIdBo.getProjectIdList());
    }


    public void verifyProjectCode(String projectCode, Long id) {
        LambdaQueryWrapper<GzxProject> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(projectCode), GzxProject::getProjectCode, projectCode);
        lqw.ne(id != null, GzxProject::getId, id);
        if (CollectionUtil.isNotEmpty(baseMapper.selectList(lqw))) {
            throw new CommonException(projectCode + "：项目编码已存在");
        }
    }

    private void setProductName(List<GzxProjectVo> gzxProjectVoList) {
        List<GzxProduct> productList = productMapper.selectList();
        Map<String, GzxProduct> productMap = productList.stream().collect(Collectors.toMap(GzxProduct::getProductCode, product -> product));
        gzxProjectVoList.forEach(s -> {
            if (productMap.containsKey(s.getProductCode())) {
                s.setProductName(productMap.get(s.getProductCode()).getProductName());
            }
        });
    }

    private void setProductName(GzxProjectVo gzxProjectVo) {
        List<GzxProduct> productList = productMapper.selectList();
        Map<String, GzxProduct> productMap = productList.stream().collect(Collectors.toMap(GzxProduct::getProductCode, product -> product));
        if (productMap.containsKey(gzxProjectVo.getProductCode())) {
            gzxProjectVo.setProductName(productMap.get(gzxProjectVo.getProductCode()).getProductName());
        }
    }

    private List<CustomVo> convertList(List<GzxProjectVo> projectVoList) {
        List<CustomVo> customVoList = new ArrayList<>();
        for (GzxProjectVo projectVo : projectVoList) {
            CustomVo customVo = new CustomVo();
            customVo.setId(Long.valueOf(projectVo.getId()));//
            customVo.setValue(projectVo.getProjectCode());
            customVo.setLabel(projectVo.getProjectName());
            customVoList.add(customVo);
        }
        return customVoList;
    }

    /**
     * 根据project
     *
     * @param projectCode
     * @return
     */
    @Override
    @DS("tjzy")
    public String getProjectNameByCode(String projectCode) {
        if (StringUtils.isBlank(projectCode)) {
            return null;
        }
        GzxProject project = baseMapper.selectOne(new LambdaQueryWrapper<GzxProject>().eq(GzxProject::getProjectCode, projectCode));
        return project.getProjectName();
    }

    /**
     * 获取项目平铺
     *
     * @return
     */
    @Override
    public Map<String, GzxProjectTileBo> getProjectTile() {
        List<GzxProject> projectList = baseMapper.selectList();
        List<GzxProduct> productList = productMapper.selectList();
        Map<String, GzxProduct> productMap = productList.stream()
                .collect(Collectors.toMap(
                        GzxProduct::getProductCode,
                        Function.identity(),
                        (a, b) -> b));
        List<GzxCompany> companyList = companyMapper.selectList();
        Map<String, GzxCompany> companyMap = companyList.stream()
                .collect(Collectors.toMap(
                        GzxCompany::getCompanyCode,
                        Function.identity(),
                        (a, b) -> b));
        Map<String, GzxProjectTileBo> tileBoMap = new HashMap<>();
        for (GzxProject project : projectList) {
            GzxProjectTileBo projectTileBo = new GzxProjectTileBo();
            if (productMap.containsKey(project.getProductCode())) {
                GzxProduct product = productMap.get(project.getProductCode());
                projectTileBo.setProductCode(product.getProductName());
                if (companyMap.containsKey(product.getCompanyCode())) {
                    GzxCompany company = companyMap.get(product.getCompanyCode());
                    projectTileBo.setCompanyCode(company.getCompanyCode());
                    projectTileBo.setCompanyName(company.getCompanyName());
                }
            }
            tileBoMap.put(project.getProjectCode(), projectTileBo);
        }
        return tileBoMap;
    }

    @Override
    public void afterPropertiesSet() {
        refreshTransCache();
    }

    private void refreshTransCache() {
        CompletableFuture.supplyAsync(() -> {
            // 使用redis能解决共享问题，但是性能没有直接取缓存的好。
            dictionaryTransService.makeUseRedis();
            try {
                TenantContext.disableTenantFilter();
                List<GzxProject> projectList = projectListService.getList();
                dictionaryTransService.refreshCache(GzxDictConstant.PROJECT, projectList.stream().collect(Collectors.toMap(GzxProject::getProjectCode, GzxProject::getProjectName)));
            } finally {
                TenantContext.enableTenantFilter();
                TenantContext.clear();
            }
            return null;
        }).exceptionally(ex -> {
            log.error("刷新项目缓存发生异常:", ex);
            return null;
        });
    }
}
